package com.mysher.devlib.uvc;

import com.mvcframework.mvccamera.Camera;
import com.mvcframework.mvccamera.CameraControl;
import com.mvcframework.mvccamera.IFrameListener;
import com.mvcframework.mvccamera.IOperateListener;
import com.mvcframework.mvccamera.StartPreviewParameter;
import com.mvcframework.mvccamera.UsbDeviceControl;
import com.mvcframework.mvccamerabase.CameraAttributes;
import com.mvcframework.mvccamerabase.Format;
import com.mvcframework.mvccamerabase.FormatType;
import com.mvcframework.mvccamerabase.Frame;
import com.mvcframework.mvcdecoder.DecoderControl;
import com.mvcframework.mvcdecoder.IDecodeResultListener;
import com.mysher.devlib.uvc.renderer.YuvGLSurfaceView;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class UvcCameraDevImpl implements UvcCameraDev {
    private final String TAG = "UvcCameraDevImpl";

    private UsbDeviceControl usbDeviceControl;
    private CameraControl cameraControl;
    private Camera camera;
    private YuvGLSurfaceView yuvGLSurfaceView;

    //private Surface surface;
    //private YUVPlayer yuvPlayer;

    private DecoderControl decoderControl;
    private Format.Resolution previewResolution;
    private FormatType previewFormatType;
    private boolean isDecoder = true;
    private int mjpegLevel;

    private PreviewListener mListener;
    private PreviewStateListener mStateListener;
    //private OnCaptureListener captureListener;

    UvcCameraDevImpl(UsbDeviceControl usbDeviceControl, Camera camera) {
        this.usbDeviceControl = usbDeviceControl;
        this.camera = camera;
    }

    @Override
    public void openCamera(IOperateListener iOperateListener) {
        //camera.getUvcCamera()
        if (cameraControl != null && cameraControl.isOpen()) {
            iOperateListener.OnFinished(true);
            return;
        }
        cameraControl = new CameraControl(camera, usbDeviceControl);
        cameraControl.open(b -> {
            if (iOperateListener != null) {
                iOperateListener.OnFinished(b);
            }
        });
    }

    @Override
    public Format[] getAllFormats() {
        if (cameraControl != null && cameraControl.isOpen()) {
            return cameraControl.getFormats();
        }
        return null;
    }

    @Override
    public Format getFormat(FormatType type) {
        if (cameraControl != null && cameraControl.isOpen()) {
            Format[] formats = cameraControl.getFormats();
            for (int i = 0; i < formats.length; i++) {
                Format format = formats[i];
                if (format.getType() == type) {
                    return format;
                }
            }
        }
        return null;
    }

    @Override
    public void setPreviewGLSurfaceView(YuvGLSurfaceView yuvGLSurfaceView) {
        this.yuvGLSurfaceView = yuvGLSurfaceView;
    }

    @Override
    public void startPreview(Format.Resolution resolution, FormatType formatType, IOperateListener operateListener) {
        previewFormatType = formatType;
        previewResolution = resolution;
        StartPreviewParameter previewParameter = new StartPreviewParameter(formatType, resolution.getWidth(),
                resolution.getHeight(), 0, iFrameListener);
        if (cameraControl != null && cameraControl.isOpen()) {
            cameraControl.startPreview(new StartPreviewParameter[]{previewParameter}, new IOperateListener() {
                @Override
                public void OnFinished(boolean b) {
                    operateListener.OnFinished(b);
                }
            });
        } else {
            operateListener.OnFinished(false);
        }
    }

    private IFrameListener iFrameListener = new IFrameListener() {
        @Override
        public void onFrameUpdated(Frame frame) {
            if (frame != null && decoderControl != null && decoderControl.isInit()) {
                decoderControl.decode(frame);
            }
            /*if (captureListener != null && frame != null) {
                if (FormatType.MJPG == frame.getType()) {
                    captureListener.onCapture(ErrorCode.MOK, frame.getFrame().clone());
                } else if (FormatType.YUY2 == frame.getType()) {
                    byte[] jpeg = Yuy2Utils.yuy2ToJpeg(frame.getFrame(), frame.getWidth(), frame.getHeight());
                    captureListener.onCapture(ErrorCode.MOK, jpeg);
                } else {
                    captureListener.onCapture(ErrorCode.ERROR_UN_SUPPORT_FORMAT, null);
                }
                captureListener = null;
            }*/

            if (mListener != null && frame != null) {
                mListener.onCameraPreview(frame.getFrame(), frame.getWidth(), frame.getHeight(), frame.getType());
            }
        }

        @Override
        public void surfaceCreated() {
            if (!isDecoder /*|| surface == null*/) {
                return;
            }
            decoderControl = new DecoderControl();
            decoderControl.setMjpgLevel(mjpegLevel == 0 ? 1 : mjpegLevel);
            decoderControl.init2(previewFormatType, previewResolution.getWidth(), previewResolution.getHeight(),
                    new IDecodeResultListener() {
                        @Override
                        public void OnDcodeResult(byte[] bytes, int width, int height, FormatType formatType) {
                            if (mListener != null) {
                                mListener.onDecode(bytes, width, height, formatType);
                            }
                            if (yuvGLSurfaceView != null) {
                                yuvGLSurfaceView.setYUVData(bytes, width, height);
                            }
                        }
                    });
            decoderControl.setCameraControl(cameraControl, 0);
            if (mStateListener != null) {
                mStateListener.onPreviewCreated(previewResolution.getWidth(), previewResolution.getHeight());
            }
           /* if (surface != null) {
                yuvPlayer = new YUVPlayer(surface, previewResolution.getWidth(), previewResolution.getHeight());
            }*/
        }

        @Override
        public void surfaceChanged(int i, int i1) {

        }

        @Override
        public void surfaceDestroyed() {
            if (decoderControl != null) {
                decoderControl.destroy();
                decoderControl = null;
            }
            if (mStateListener != null) {
                mStateListener.onPreviewDestroy();
            }
            /*if (yuvPlayer != null) {
                yuvPlayer.destroy();
                yuvPlayer = null;
            }*/
        }
    };

    @Override
    public void stopPreview(IOperateListener operateListener) {
        if (cameraControl != null && cameraControl.isPreviewing()) {
            cameraControl.stopPreview(b -> {
                operateListener.OnFinished(b);
            });
        } else {
            operateListener.OnFinished(true);
        }
        previewResolution = null;
        previewFormatType = null;
        mjpegLevel = 0;
    }

    @Override
    public void closeDevice(IOperateListener iOperateListener) {
        yuvGLSurfaceView = null;
        if (cameraControl != null && cameraControl.isOpen()) {
            cameraControl.close(iOperateListener);
        }
    }

    @Override
    public void setCameraAttributesValue(CameraAttributes cameraAttributes, int value) {
        if (cameraControl != null && cameraControl.isOpen()) {
            boolean support = cameraControl.isSupportCameraAttributes(cameraAttributes);
            if (support) {
                cameraControl.setCameraAttributesValueAbs(cameraAttributes, value);
            }
        }
    }

    @Override
    public CameraAttrInfo[] getCameraAttributesValues() {
        if (cameraControl == null || !cameraControl.isOpen()) {
            return null;
        }
        CameraAttributes[] values = CameraAttributes.values();
        CameraAttrInfo[] cameraAttrInfos = new CameraAttrInfo[6];
        for (int i = 0; i < 6; i++) {
            CameraAttrInfo cameraAttributesValue = getCameraAttributesValue(values[i], i);
            cameraAttrInfos[i] = cameraAttributesValue;
        }
        return cameraAttrInfos;
    }

    private CameraAttrInfo getCameraAttributesValue(CameraAttributes attributes, int index) {
        CameraAttrInfo cameraAttrInfo = new CameraAttrInfo();
        cameraAttrInfo.setId(index);
        cameraAttrInfo.setName(CameraAttrInfo.AttrIndexToName(index));
        boolean support = cameraControl.isSupportCameraAttributes(attributes);
        cameraAttrInfo.setSupport(support);
        if (support) {
            cameraAttrInfo.setValue(cameraControl.getCameraAttributesValueAbs(attributes));
            cameraAttrInfo.setDefVal(cameraControl.getCameraAttributesDefaultValueAbs(attributes));
            cameraAttrInfo.setMax(cameraControl.getCameraAttributesMaxValueAbs(attributes));
            cameraAttrInfo.setMin(cameraControl.getCameraAttributesMinValueAbs(attributes));
        }
        return cameraAttrInfo;
    }

    @Override
    public void resetCameraAttributes(CameraAttributes cameraAttributes) {
        if (cameraControl != null && cameraControl.isOpen()) {
            boolean support = cameraControl.isSupportCameraAttributes(cameraAttributes);
            if (support) {
                cameraControl.resetCameraAttributesValue(cameraAttributes);
            }
        }
    }

    public void setPreviewListener(PreviewListener mListener) {
        this.mListener = mListener;
    }

    @Override
    public void setPreviewStateListener(PreviewStateListener mListener) {
        mStateListener = mListener;
    }

    @Override
    public void setDecode(boolean isDecode) {
        this.isDecoder = isDecode;
    }


    @Override
    public String getSn() {
        if (cameraControl != null && cameraControl.isOpen()) {
            cameraControl.getSN();
        }
        return null;
    }

    @Override
    public boolean isOpen() {
        if (cameraControl != null) {
            return cameraControl.isOpen();
        }
        return false;
    }

    @Override
    public boolean isNativeOpen() {
        if (cameraControl != null) {
            Class<? extends CameraControl> clazz = cameraControl.getClass();
            try {
                Method isNativeOpen = clazz.getMethod("isNativeOpen");
                Object invoke = isNativeOpen.invoke(cameraControl);
                if (invoke != null) {
                    return (boolean) invoke;
                }
            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    @Override
    public boolean isPreview() {
        if (cameraControl != null) {
            return cameraControl.isPreviewing();
        }
        return false;
    }


    @Override
    public Format.Resolution getPreviewSize() {
        return previewResolution;
    }

    @Override
    public void setMjpegLevel(int mjpegLevel) {
        this.mjpegLevel = mjpegLevel;
    }


}
